// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "netclientjob.h"

#include <QFile>
#include <QHttpMultiPart>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDBusReply>
#include <QTimer>
#include <QUuid>

#include <crypt.h>
#include <random>

enum LocalUserType {
    StandardUser = 0,
    Administrator,
    Customized
};

/**
 * @brief crypt函数是否支持SM3算法
 * crypt使用固定的key和salt进行加密，把加密结果与已知的正确结果进行比对，相等则支持，反之不支持
 * @return true 支持
 * @return false 不支持
 */
inline bool supportSM3()
{
    char password[] = "Hello world!";
    char salt[] = "$8$saltstring";
    const QString cryptResult = "$8$saltstring$6RCuSuWbADZmLALkvsvtcYYzhrw3xxpuDcqwdPIWxTD";
    return crypt(password, salt) == cryptResult;
}

inline QString cryptUserPassword(const QString &password)
{
    /*
        NOTE(kirigaya): Password is a combination of salt and crypt function.
        slat is begin with $6$, 16 byte of random values, at the end of $.
        crypt function will return encrypted values.
     */
    const QString seedChars("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
    char salt[] = "$6$................$";
    if (supportSM3()) {
        qInfo() << "SM3 is supported";
        salt[1] = '8';
    }

    std::random_device r;
    std::default_random_engine e1(r());
    std::uniform_int_distribution<int> uniform_dist(0, seedChars.size() - 1); //seedChars.size()是64，生成随机数的范围应该写成[0, 63]。

    // Random access to a character in a restricted list
    for (int i = 0; i != 16; i++) {
        salt[3 + i] = seedChars.at(uniform_dist(e1)).toLatin1();
    }

    return crypt(password.toUtf8().data(), salt);
}

NetClientJob::NetClientJob(QObject *parent)
    : QObject(parent)
    , m_rsaHelper(nullptr)
    , m_networkAccessManager(nullptr)
    , m_checkHttpSrvValidityNetReply(nullptr)
    , m_currentIfcType(InterfaceType::None)
    , m_netReply(nullptr)
    , m_qrStatus(NotScaned)
    , m_accoutDbusIfc(nullptr)
{
    // register meta type
    qRegisterMetaType<QrStatus>("QrStatus");

    m_httpAddress = "http://www.baidu.com";

    m_rsaHelper = new RsaHelper(this);
    m_networkAccessManager = new QNetworkAccessManager(this);

    m_accoutDbusIfc = new QDBusInterface("com.deepin.daemon.Accounts",
                                        "/com/deepin/daemon/Accounts",
                                        "com.deepin.daemon.Accounts",
                                        QDBusConnection::systemBus(), this);



    // post init
    asynCheckHttpSrvValidity();

    // encrypt & decrypt test
    QString publicKey = "-----BEGIN PUBLIC KEY-----\n"
            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxCOnnOW0ntYdfWLL3TTk78SEQiDH9ugioU0qFTYVUH2L/qsnFaouPtIqICc3b8QjlkRq3hjo6+bEEOtrxxeaOfY5RXsDUsVYOin01/kTNUHg2/1wFnquTYll2ZLrCtcn+KRv93gIEKCbbBDAukIvgkF6A8LCzGcw0MqfHdZZIiHijxBraAOMsCYHAUeIY4lgbRtHDxypSiePb/bePrASOZXnoQxcdFpzpEyrx+XvlAMt3t93OdaHFYeeY9EmToERK2q9gsZD/JxFaHKP6TvLFNqh0pHFX2dHICFilGm0SP6Hc59W30MOFpjVdpek3DqNaur6cqw9To89MshiWrpNbwIDAQAB\n"
            "-----END PUBLIC KEY-----";

    m_rsaHelper->setPublicKey(publicKey);
    QString privateKey = "-----BEGIN RSA PRIVATE KEY-----\n"
            "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEI6ec5bSe1h19YsvdNOTvxIRCIMf26CKhTSoVNhVQfYv+qycVqi4+0iogJzdvxCOWRGreGOjr5sQQ62vHF5o59jlFewNSxVg6KfTX+RM1QeDb/XAWeq5NiWXZkusK1yf4pG/3eAgQoJtsEMC6Qi+CQXoDwsLMZzDQyp8d1lkiIeKPEGtoA4ywJgcBR4hjiWBtG0cPHKlKJ49v9t4+sBI5leehDFx0WnOkTKvH5e+UAy3e33c51ocVh55j0SZOgRErar2CxkP8nEVoco/pO8sU2qHSkcVfZ0cgIWKUabRI/odzn1bfQw4WmNV2l6TcOo1q6vpyrD1Ojz0yyGJauk1vAgMBAAECggEAI1eNXz8g0bIhNDO2KlDao72UW1oOzhW8D7aYy6OoKY3FyQjMDSJSHO2/u3V1jsUX6H7Bhu2UItW9JJNXI1PEbYdJgJSO375BjJF81eHCrUkGnH1JUjOe7sfAO3k2swhb4ni22C+fvGdEOi+2mplMeDsWIlFYyn4ZlLW+ACFchEKoC4T+osSPCfq6NYH2b8h93GEFJgBAKoZ7EffIzWi2SaaTU3U4BDbKDZ8olO5u4aRUQOr+yxgp8A3mqFkbKfJ2MpWbf0zdeZN4tKuwV2QeuHew7J4xrrn4I/H/r3lE49J7IA53DI2y1ExnaAB9fjyLvzvvxvTHa3ct4wJ6gyNZCQKBgQDk4U+PfgX+Ye47GAga7Ve+SCd7nyIeoNh1usyVGq3bb6GQIP9kpDS3EBQQLjJ2Ez/zBd7bcPmZNmSH6FRf5gzWP12tuxQV2kY6OGBcoIdnTyy1YjstS4LFqiCvW1JZbRV6Lkedt67I4GUHagZy/h1VC+sKhB9yBa9375UqGXpyxQKBgQDbYTTFHQ9883++NI4DTuR83D7gjTxgEXWnQf24TZ63gdrp3zT53Paqxao4RKKBJ2DKZYQowdcTSKY0dUrhyWLc1j8uJ0oxou709t/+MSFXxXQkZ9wEmfWRyV/w8+qf4YnoFK7/hbDE5b+zrevuBS2AQulTkWhYNeR9ImoZHIHyowKBgAu3iRYkcnQaWVLHISsXuWUxVmwasml0/H/SZ0S+z+Wq6k9xkQF68oPom85UPxsSUzTCuSzstKpmQXE/sIoUQdX5+na5XAbeXLgASNaVFTlxsS078SGZewFZe0De4PFZBz9w/ROS4qy/6AwgHmJmpePDr22jY+S3a8stBarZEQ6tAoGBAK5hYE7mwK7z5zDMGa5rgZf2gkyAN+OtPTZMcF+V43m+0MJiWHvctn4cTSgY9otvP7LiauDy5AFCGEtOiM1dBSbBbstDE+jMuOEjc/1cFELug1mE7REDSH4v8gFYAcJAxxwhhNE79b0tWup6bzVuDDMN/OYeiTDE9fC58FgxnuG9AoGAXULq+pwXCCc1bJ8CT2nKhWyZcaPtMfmsCrjQPApehsMF3HyW4qPOEkSaTYpAIW/DGVWWqqireZjebVi7+w3nlyNKCs6laMPmxDkjXdQtHBA57ikdH/iNo8MxUYLL07arJHqE0rGXUJpGNumfbQIOSj94xxrLrSTTwVPjdB4v7YM=\n"
            "-----END RSA PRIVATE KEY-----";
    m_rsaHelper->setPrivateKey(privateKey);

    QString passwd = "sdfdasfasfasrbg98989080";
    QString encryptCode = m_rsaHelper->encrypt(passwd);
    qInfo() << Q_FUNC_INFO << "m_rsaHelper->encrypt(passwd)" << encryptCode;
//    encryptCode = "hSvP/jvHXHmWAEK7UXP1x1mlr9TzB0zOv/phNxQqxSkzkPaz0nb2GGESlEcSfAgEiqp3kfKFbi021DtsaMMsEGW5UjFRj5GGCfTT6nSxl5N1ZSziwC4f3XrkgAj4GCmctlOyObR1htUOTwU4Ir4d0RgluIiJN/+8QHgTm+yqxrrZiIBzCP0eu6Gd0FPNhL0Kpm7DKvXKsJGEKJlEDTHcKCE50PUWR6AhXbaG3n2oj4MSbJioXvRE4U7JAs0vNlNML8tagSs62SJ0gR2CLeMrmZGfXb80iEICiyqFQHuh9EJtPH4eIM7YfhT2MpjCDFXQ7X+ugwayyu4IahxjUslDTg==";
    qInfo() << Q_FUNC_INFO << "m_rsaHelper->decrypt(passwd)" << m_rsaHelper->decrypt(encryptCode);

}

NetClientJob::~NetClientJob()
{

}

void NetClientJob::quit()
{

}

QString NetClientJob::getIdTocken()
{
    return m_userIdToken;
}

void NetClientJob::onRequestRegisterClient(const QString &clientCode)
{
    qDebug() << Q_FUNC_INFO << clientCode;
    if (InterfaceType::None != m_currentIfcType) {
        qWarning() << Q_FUNC_INFO << m_currentIfcType << "type task is in working";
        return;
    }
    m_currentIfcType = InterfaceType::RegisterClient;
    m_clientCode = clientCode;

    QByteArray inputData = "clientCode=" + clientCode.toUtf8();
    // url编码
    inputData.toPercentEncoding();

    QUrl url(m_httpAddress + "/client/register");
    QNetworkRequest req(url);
    req.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded");

    m_netReply = m_networkAccessManager->post(req, inputData);
    connect(m_netReply, &QNetworkReply::finished, this, &NetClientJob::onHttpDataDownloadFinished);
}

void NetClientJob::onRequestGetQrCode()
{
    qDebug() << Q_FUNC_INFO;
    if (InterfaceType::None != m_currentIfcType) {
        qWarning() << Q_FUNC_INFO << m_currentIfcType << "type task is in working";
        return;
    }
    m_currentIfcType = InterfaceType::GetQr;
    m_qrStatus = QrStatus::NotScaned;
    QUrl url(m_httpAddress + "/getQr");
    QNetworkRequest req(url);
    m_netReply = m_networkAccessManager->get(req);
    connect(m_netReply, &QNetworkReply::finished, this, &NetClientJob::onHttpDataDownloadFinished);
}

void NetClientJob::onRequestCheckQrCode()
{
    qDebug() << Q_FUNC_INFO;
    if (InterfaceType::None != m_currentIfcType) {
        qDebug() << Q_FUNC_INFO << m_currentIfcType << "type task is in working";
        Q_EMIT checkQrCodeFinished(true, m_qrStatus);
        return;
    }
    // 当前二维码状态为“同意登陆”或“过期”时，不在去查询二维码状态
    if (QrStatus::AcceptLogin == m_qrStatus || Expired == m_qrStatus) {
        qDebug() << Q_FUNC_INFO << "m_qrStatus: AcceptLogin or Expired, no need check from srv" << m_qrStatus;
        Q_EMIT checkQrCodeFinished(true, m_qrStatus);
        return;
    }
    m_currentIfcType = InterfaceType::CheckQr;

    QByteArray inputData = "key=" + m_qrKey.toUtf8();
    // url编码
    inputData.toPercentEncoding();

    QUrl url(m_httpAddress + "/checkQr");
    QNetworkRequest req(url);
    req.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded");

    m_netReply = m_networkAccessManager->post(req, inputData);
    connect(m_netReply, &QNetworkReply::finished, this, &NetClientJob::onHttpDataDownloadFinished);
}

void NetClientJob::onRequestQueryLocalUserInfo()
{
    qDebug() << Q_FUNC_INFO;
    if (InterfaceType::None != m_currentIfcType) {
        qWarning() << Q_FUNC_INFO << m_currentIfcType << "type task is in working";
        return;
    }
    m_currentIfcType = InterfaceType::QueryLocalUserInfo;

    QByteArray inputData = "clientCode=" + m_clientCode.toUtf8() + "&"
                        + "igwUserid=" + m_userId.toUtf8();
    // url编码
    inputData.toPercentEncoding();

    QUrl url(m_httpAddress + "/client/query");
    QNetworkRequest req(url);
    req.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded");

    m_netReply = m_networkAccessManager->post(req, inputData);
    connect(m_netReply, &QNetworkReply::finished, this, &NetClientJob::onHttpDataDownloadFinished);
}

void NetClientJob::onRequestSaveLocalUserInfo(const QString &localUserName,
                                              const QString &localUserFullName,
                                              const QString &localUserPasswd)
{
    qDebug() << Q_FUNC_INFO << localUserName << localUserFullName;
    if (InterfaceType::None != m_currentIfcType) {
        qWarning() << Q_FUNC_INFO << m_currentIfcType << "type task is in working";
        return;
    }

    m_currentIfcType = InterfaceType::SaveLocalUserInfo;

    m_localUserName = localUserName;
    // rsa加密
    QString encryptedLocalUserPasswd = m_rsaHelper->encrypt(localUserPasswd);
    QByteArray inputData =
            "clientCode=" + m_clientCode.toUtf8() + "&"
            + "igwUserid=" + m_userId.toUtf8() + "&"
            + "acc=" + m_localUserName.toUtf8() + "&"
            + "mm=" + encryptedLocalUserPasswd.toUtf8() + "&"
            + "userName=" + localUserFullName.toUtf8();
    // url编码
    inputData.toPercentEncoding();

    QUrl url(m_httpAddress + "/client/save");
    QNetworkRequest req(url);
    req.setHeader(QNetworkRequest::KnownHeaders::ContentTypeHeader, "application/x-www-form-urlencoded");

    m_netReply = m_networkAccessManager->post(req, inputData);
    connect(m_netReply, &QNetworkReply::finished, this, &NetClientJob::onHttpDataDownloadFinished);
}

void NetClientJob::onRequestCheckFace(const QString &imgData)
{
    qDebug() << Q_FUNC_INFO;
    if (InterfaceType::None != m_currentIfcType) {
        qWarning() << Q_FUNC_INFO << m_currentIfcType << "type task is in working";
        return;
    }

    m_currentIfcType = InterfaceType::CheckFace;

    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

    QHttpPart filePart;
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader,
                       "form-data; name=\"file\"; filename=\"faceImg\"");
    QByteArray imgFileData = QByteArray::fromBase64(imgData.toUtf8());
    filePart.setHeader(QNetworkRequest::ContentLengthHeader, imgFileData.size());

    filePart.setBody(imgFileData);
    multiPart->append(filePart);

    QUrl url(m_httpAddress + "/checkFace");
    QNetworkRequest req(url);
    req.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/from-data;boundary="
                  + multiPart->boundary());
    m_netReply = m_networkAccessManager->post(req, multiPart);
    multiPart->setParent(m_netReply);
    connect(m_netReply, &QNetworkReply::finished, this, &NetClientJob::onHttpDataDownloadFinished);
}

void NetClientJob::onRequestTryCreateLocalUser()
{
    qDebug() << Q_FUNC_INFO;
    QString localUserName = QString("%1%2").arg(m_userAdviceName).arg(m_userId).left(10);
    QString localUserPasswd = QUuid::createUuid().toString(QUuid::WithoutBraces).remove("-");
    if (!isLocalUserExist(localUserName)) {
        // 创建用户
        createLocalUser(localUserName, m_userDisplayName, localUserPasswd);
    }

    onRequestSaveLocalUserInfo(localUserName, m_userDisplayName, localUserPasswd);
}

void NetClientJob::onRequestCheckHttpSrvValidity()
{
    asynCheckHttpSrvValidity();
}

void NetClientJob::onRequestStopHttpReply()
{
    stopHttpReply();
}

void NetClientJob::onHttpDataDownloadFinished()
{
    qInfo() << Q_FUNC_INFO;
    QByteArray netReplyContent = m_netReply->readAll();
    switch (m_currentIfcType) {
    case RegisterClient:
        parseDataOfRegisterClient(netReplyContent);
        break;
    case GetQr:
        parseDataOfGetQr(netReplyContent);
        break;
    case CheckQr:
        parseDataOfCheckQr(netReplyContent);
        break;
    case QueryLocalUserInfo:
        parseDataOfQueryLocalUserInfo(netReplyContent);
        break;
    case SaveLocalUserInfo:
        parseDataOfSaveLocalUserInfo(netReplyContent);
        break;
    case CheckFace:
        parseDataOfCheckFace(netReplyContent);
        break;
    default:
        break;
    }

    m_currentIfcType = InterfaceType::None;
    m_netReply->deleteLater();
    m_netReply = nullptr;
}

void NetClientJob::parseDataOfRegisterClient(const QByteArray &content)
{
    QJsonParseError err;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(content, &err);
    if (err.error != QJsonParseError::ParseError::NoError) {
        qDebug() << Q_FUNC_INFO << err.errorString() << err.error;
        Q_EMIT registerClientFinished(false, m_clientCode);
        return;
    }

    QString codeValue = jsonDoc.object().value("code").toString();
    QString msgValue = jsonDoc.object().value("msg").toString();
    if ("-1" == codeValue) {
        qDebug() << Q_FUNC_INFO << "Register Client failed!" << codeValue << msgValue;
        Q_EMIT registerClientFinished(false, m_clientCode);
        return;
    }
    QJsonObject resultValue = jsonDoc.object().value("result").toObject();
    QString publicKey = resultValue.value("pem").toString();
    publicKey = "MIIDijCCAnKgAwIBAgIGAYhCmiDYMA0GCSqGSIb3DQEBCwUAMHgxFzAVBgNVBAMTDnd3dy5hb3N0YXIuY29tMRgwFgYDVQQLDA/l";
    m_rsaHelper->setPublicKey(publicKey);
    QString privateKey = resultValue.value("key").toString();
    privateKey = "MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQCa2NcFCMpO78J3EU1GcUlT8+xTylu1JKWfaoVJHqCDGxQIhUUC";
    m_rsaHelper->setPrivateKey(privateKey);

    Q_EMIT registerClientFinished(true, m_clientCode);
}

void NetClientJob::parseDataOfGetQr(const QByteArray &content)
{
    QJsonParseError err;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(content, &err);
    if (err.error != QJsonParseError::ParseError::NoError) {
        qDebug() << Q_FUNC_INFO << err.errorString() << err.error;
        Q_EMIT getQrCodeFinished(false, "");
        return;
    }

    QString codeValue = jsonDoc.object().value("code").toString();
    QString msgValue = jsonDoc.object().value("msg").toString();
    if ("-1" == codeValue) {
        qDebug() << Q_FUNC_INFO << "get qr failed!" << codeValue << msgValue;
        Q_EMIT getQrCodeFinished(false, "");
        return;
    }
    QJsonObject resultValue = jsonDoc.object().value("result").toObject();
    QString resultQrValue = resultValue.value("qr").toString();
    m_qrKey = resultValue.value("key").toString();

    qInfo() << Q_FUNC_INFO << m_qrKey;
    Q_EMIT getQrCodeFinished(true, resultQrValue);
}

void NetClientJob::parseDataOfCheckQr(const QByteArray &content)
{
    QJsonParseError err;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(content, &err);
    if (err.error != QJsonParseError::ParseError::NoError) {
        qDebug() << Q_FUNC_INFO << err.errorString() << err.error;
        Q_EMIT checkQrCodeFinished(true, NotScaned);
        return;
    }

    QString codeValue = jsonDoc.object().value("code").toString();
    QString msgValue = jsonDoc.object().value("msg").toString();
    if ("-1" == codeValue) {
        qDebug() << Q_FUNC_INFO << "check qr failed!" << codeValue << msgValue;
        m_qrStatus = AuthFailed;
        Q_EMIT checkQrCodeFinished(true, m_qrStatus);
        return;
    }
    QJsonObject resultValue = jsonDoc.object().value("result").toObject();
    QString resultStatusValue = resultValue.value("code").toString();
    m_qrStatus = NotScaned;
    if ("1" == resultStatusValue) {
        m_qrStatus = AcceptLogin;
    } else if ("2" == resultStatusValue) {
        m_qrStatus = NotScaned;
    } else if ("3" == resultStatusValue) {
        m_qrStatus = ScandedNotAccept;
    } else if ("4" == resultStatusValue) {
        m_qrStatus = Expired;
    }

    m_userId = resultValue.value("userId").toString();
    m_userDisplayName = resultValue.value("name").toString();
    m_userAdviceName = resultValue.value("adviceName").toString();
    QString rusultIdTokenValue = resultValue.value("idToken").toString();
    if (!rusultIdTokenValue.isEmpty()) {
        m_userIdToken = rusultIdTokenValue;
    }
    qInfo() << Q_FUNC_INFO << "idToken" << m_userIdToken;

    Q_EMIT checkQrCodeFinished(true, m_qrStatus);
}

void NetClientJob::parseDataOfQueryLocalUserInfo(const QByteArray &content)
{
    QJsonParseError err;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(content, &err);
    if (err.error != QJsonParseError::ParseError::NoError) {
        qDebug() << Q_FUNC_INFO << err.errorString() << err.error;
        Q_EMIT queryLocalUserInfoFinished(false, "");
        return;
    }

    QString codeValue = jsonDoc.object().value("code").toString();
    QString msgValue = jsonDoc.object().value("msg").toString();
    if ("-1" == codeValue) {
        qDebug() << Q_FUNC_INFO << "Query Local User Info failed!" << codeValue << msgValue;
        Q_EMIT queryLocalUserInfoFinished(false, "");
        return;
    }
    QJsonObject resultValue = jsonDoc.object().value("result").toObject();
    QString resultLocalUserNameValue = resultValue.value("acc").toString();
    QString resultLocalUserPasswdValue = resultValue.value("mm").toString();
    // 解密
    QString decryptedLocalUserPasswd = m_rsaHelper->decrypt(resultLocalUserPasswdValue);
    QString resultUserNameValue = resultValue.value("userName").toString();
    QString resultCreatedTimeValue = resultValue.value("createdTime").toString();
    QString resultUpdateTimeValue = resultValue.value("updateTime").toString();

    Q_EMIT queryLocalUserInfoFinished(true, resultLocalUserNameValue);
}

void NetClientJob::parseDataOfSaveLocalUserInfo(const QByteArray &content)
{
    QJsonParseError err;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(content, &err);
    if (err.error != QJsonParseError::ParseError::NoError) {
        qDebug() << Q_FUNC_INFO << err.errorString() << err.error;
        Q_EMIT saveLocalUserInfoFinished(false, "");
        return;
    }

    QString codeValue = jsonDoc.object().value("code").toString();
    QString msgValue = jsonDoc.object().value("msg").toString();
    if ("-1" == codeValue) {
        qDebug() << Q_FUNC_INFO << "Save Local User Info failed!" << codeValue << msgValue;
        Q_EMIT saveLocalUserInfoFinished(false, "");
        return;
    }

    Q_EMIT saveLocalUserInfoFinished(true, m_localUserName);
}

void NetClientJob::parseDataOfCheckFace(const QByteArray &content)
{
    QJsonParseError err;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(content, &err);
    if (err.error != QJsonParseError::ParseError::NoError) {
        qDebug() << Q_FUNC_INFO << err.errorString() << err.error;
        return;
    }

    QString codeValue = jsonDoc.object().value("code").toString();
    QString msgValue = jsonDoc.object().value("msg").toString();
    if ("-1" == codeValue) {
        qDebug() << Q_FUNC_INFO << "check qr failed!" << codeValue << msgValue;
        return;
    }
    QJsonObject resultValue = jsonDoc.object().value("result").toObject();
    bool resultStatusValue = resultValue.value("checkResult").toBool();
    m_userId = resultValue.value("userId").toString();
    m_userDisplayName = resultValue.value("name").toString();
    m_userAdviceName = resultValue.value("adviceName").toString();
    QString rusultIdTokenValue = resultValue.value("idToken").toString();
    if (!rusultIdTokenValue.isEmpty()) {
        m_userIdToken = rusultIdTokenValue;
    }
    qInfo() << Q_FUNC_INFO << "idToken" << m_userIdToken;

    Q_EMIT checkFaceFinished(resultStatusValue);
}

bool NetClientJob::isLocalUserExist(const QString &localUserName)
{
    QDBusReply<QString> reply = m_accoutDbusIfc->call("FindUserByName", localUserName);
    if (!reply.isValid()) {
       qWarning() << Q_FUNC_INFO <<  "FindUserByName failed";
       return false;
    }

    return !reply.value().isEmpty();
}

bool NetClientJob::createLocalUser(const QString &localUserName, const QString &fullName, const QString &passwd)
{
    QDBusReply<QDBusObjectPath> reply = m_accoutDbusIfc->call("CreateUser", localUserName, fullName, LocalUserType::StandardUser);
    if (!reply.isValid()) {
       qWarning() << Q_FUNC_INFO <<  "CreateUser failed";
       return false;
    }

    QDBusObjectPath dbusObjPath = reply.value();
    QDBusInterface *userIfc = new QDBusInterface("com.deepin.daemon.Accounts",
                                                 dbusObjPath.path(),
                                                 "com.deepin.daemon.Accounts.User",
                                                 QDBusConnection::systemBus(), this);
    QDBusReply<void> setPasswordReply = userIfc->call("SetPassword", cryptUserPassword(passwd));
    if (!setPasswordReply.isValid()) {
       qWarning() << Q_FUNC_INFO <<  "set Password failed";
       return false;
    }

    return true;
}

void NetClientJob::asynCheckHttpSrvValidity()
{
    if (m_checkHttpSrvValidityNetReply) {
        return;
    }

    QUrl url(m_httpAddress);
    QNetworkRequest req(url);
    req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    m_checkHttpSrvValidityNetReply = m_networkAccessManager->post(req, "");
    connect(m_checkHttpSrvValidityNetReply, &QNetworkReply::finished, this, [this]{
        if (QNetworkReply::NetworkError::NoError == m_checkHttpSrvValidityNetReply->error()) {
            Q_EMIT this->checkHttpSrvValidityFinished(true);
        } else {
            Q_EMIT this->checkHttpSrvValidityFinished(false);
        }

        m_checkHttpSrvValidityNetReply->deleteLater();
        m_checkHttpSrvValidityNetReply = nullptr;
    });

    // 最大2s等待时间后，结束检测请求
    QTimer::singleShot(2000, this, [this] {
        if (m_checkHttpSrvValidityNetReply) {
            m_checkHttpSrvValidityNetReply->abort();
        }
    });
}

void NetClientJob::stopHttpReply()
{
    if (m_netReply) {
        m_netReply->abort();
    }
}
